General: Add opt-in <search> element support to the core search form#11913
General: Add opt-in <search> element support to the core search form#11913adamsilverstein wants to merge 2 commits into
<search> element support to the core search form#11913Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
|
I'd be concerned about breaking sites using CSS selectors like Themes using the |
Good point. I wonder if we can just leave the role on form and still add the search wrapper? |
|
I think that would be safer, yes. I couldn't find any descendant selectors being used like But then you'd have a |
Right, I don't know if thats better or worse, I'm curious to hear what @joedolson thinks. |
|
I'd definitely be worried about this impacting theme CSS - there's also the potential use of direct descendant selectors that could cause problems, e.g The default search form should possibly also come with an I tested the different behaviors having nested roles, and unfortunately that does result in the landmark being announced twice. Codepen: https://codepen.io/joedolson/full/RNogReV In NVDA, the first landmark is announced as "Named Search Region search landmark search landmark". Without the |
|
My best idea for a path forward is a new option in get_search_form args to make it opt in to get the search wrapper (removing the current aria role); leaving core themes unchanged. Then perhaps in the dev note we can mention that at some point this will become the fault and plan to swap that at a later time. |
The HTML `<search>` element is in Baseline and carries an implicit ARIA landmark role of `search`, expressing natively what `get_search_form()` currently does with a manual `role="search"` attribute. Adopting it unconditionally is not back-compatible: wrapping the `<form>` in a new element breaks direct-child CSS selectors (e.g. `.search-container > form`) and reparents the form for flex/grid layouts, dropping `role="search"` breaks `form[role="search"]` selectors, and keeping the role alongside the wrapper produces nested, double-announced search landmarks. Make the wrapper opt in instead: - Add a `search-element` theme support feature. Themes that have audited their CSS declare `add_theme_support( 'search-element' )` to enable it. - Add a `wrap_in_search` argument to `get_search_form()`, defaulting to `current_theme_supports( 'search-element' )`. The `search_form_args` filter can toggle it site-wide, and a per-call value overrides both. When enabled (html5 format only), the form is wrapped in `<search>`, `role="search"` is dropped to avoid a nested landmark, and any `aria_label` names the `<search>` element. The default output, the xhtml fallback, and the bundled classic themes are left unchanged. Add unit tests covering the default and wrapped markup, aria-label placement, the xhtml fallback, the filter, and the theme-support default. See #65288.
657f809 to
540ac7a
Compare
<search> element support to the core search form
|
Following up on my note above about making this opt-in: I've reworked the PR along those lines, and added theme support as a second (theme-level) way to opt in. What changed The
When enabled, the form is wrapped in How this addresses the feedback
The bundled classic themes are intentionally left untouched (they ship their own Trac ticket: https://core.trac.wordpress.org/ticket/65288 Plan, per the ticket: ship opt-in in 7.1 with a dev note, and revisit flipping the default (e.g. for block themes first) once the ecosystem has had time to adapt. Tests live in |
… forms. Twenty Sixteen, Twenty Seventeen, Twenty Twenty, and Twenty Twenty-One ship their own `searchform.php`, so the `wrap_in_search` argument added to `get_search_form()` does not reach them automatically. Read the argument in each template so a site that opts in (via the `search-element` theme support, the `wrap_in_search` argument, or the `search_form_args` filter) gets the `<search>` landmark in these themes too. When wrapping, the form is enclosed in `<search>` and `role="search"` is dropped from the `<form>` to avoid a nested landmark. In Twenty Twenty and Twenty Twenty-One the `aria_label` moves onto `<search>`, since a named `<form>` without the role would otherwise expose a second landmark. The default output of all four templates is unchanged; the wrapper is only emitted when the argument is set. See #65288.
|
Added a second commit so the four bundled classic themes (Twenty Sixteen, Twenty Seventeen, Twenty Twenty, Twenty Twenty-One) honor the opt-in too, since they ship their own Their default output is unchanged (byte-for-byte); the Verified by rendering each template in both states. The description's scope/test sections are updated accordingly. |
|
@westonruter I reworked this PR to make the search wrapper opt in, via add_theme_support or as a parameter on get_search_form. That eliminates the breakage risk and gives us a path to adoption over time, perhaps even making it the default in the future. For now though, this would let theme builders adopt the modern approach, and maybe core can use it for a new core theme or block. |
Summary
Adds opt-in support for the HTML
<search>landmark element inget_search_form()(the function behind core's default search markup and the search widget).Trac ticket: https://core.trac.wordpress.org/ticket/65288
Why opt-in?
The
<search>element is in Baseline (Chrome 118+, Firefox 118+, Safari 17+, Edge 118+) and carries an implicit ARIA role ofsearch. But adopting it unconditionally is not back-compatible:role="search"breaksform[role="search"]CSS selectors (used by themes in the wild).<search>breaks direct-child selectors like.search-container > formand reparents the form for flex/grid layouts - regardless of whether the role is kept.role="search"alongside<search>produces nestedsearchlandmarks, which NVDA announces twice ("search landmark search landmark").There is no way to add the native landmark without a new wrapper node, so the safe path is to make it opt-in now and plan to change the default later.
What this adds
1. A
search-elementtheme support feature. A theme that has audited its CSS opts in once:2. A
wrap_in_searchargument onget_search_form(), defaulting tocurrent_theme_supports( 'search-element' ):The existing
search_form_argsfilter can enable it site-wide; a per-call value overrides the theme default.When enabled (html5 format only): the
<form>is wrapped in<search>,role="search"is dropped from the form to avoid a nested landmark, and anyaria_labelnames the<search>element.Scope and backward compatibility
<search>does not exist in XHTML 1.x).searchform.phpoutput is unchanged (byte-for-byte), and they emit the<search>wrapper only when a site opts in. In Twenty Twenty / Twenty Twenty-One thearia_labelmoves onto<search>when wrapping.core/searchblock is handled in Gutenberg: Search block: Render in the semantic <search> element gutenberg#78485Migration plan
Test plan
New tests in
tests/phpunit/tests/general/getSearchForm.phpcover:role="search"and is not wrapped.wrap_in_searchwraps the form in<search>and dropsrole="search".aria_labellands on<search>(not the inner form) when wrapping; on the form by default.wrap_in_search.search_form_argsfilter can enable wrapping site-wide.add_theme_support( 'search-element' )enables wrapping by default; an explicitwrap_in_search => falseoverrides it.9 tests, 22 assertions, passing.
The four bundled
searchform.phptemplates were verified by rendering each in both states: default output is byte-identical to trunk, and the opt-in output wraps the form in<search>, dropsrole="search", and (Twenty Twenty / Twenty Twenty-One) placesaria_labelon<search>.References